package org.ms.nerver.governor.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 基于JDK实现动态代理工厂
 * @author lry
 */
public abstract class JDKAbstractProxyFactory implements ProxyService,InvocationHandler {

	private Object object;

	private ConcurrentHashMap<String, InvocationHandler> invokerCache = new ConcurrentHashMap<String, InvocationHandler>();

	public JDKAbstractProxyFactory(Object object) {
		super();
		this.object = object;
	}

	/**
	 * 在代理实例上处理方法调用并返回结果
	 * 
	 * @param proxy 代理类
	 * @param method 被代理的方法
	 * @param args 该方法的参数数组
	 */
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if(proxy==null||object==null){
			throw new RuntimeException("proxy或method不能为空");
		}
		
		doBefore(proxy, method, args);// 调用之前
		Object result = doInvoke(method, object, args);// 调用原始对象的方法
		doAfter(proxy, method, args,result);// 调用之后
		
		return result;
	}
	
	public Object doInvoke(Method method, Object obj, Object[] args,Object...others) throws Throwable {
		return method.invoke(obj, args);
	}
	
	public <T> T getService(Class<T> clazz) throws Throwable {
		return getService(clazz, new ProxyConfig());
	}
	
	@SuppressWarnings("unchecked")
	public <T> T getService(Class<T> clazz, ProxyConfig config) throws Throwable {
		String module = config.getModule();
		if (module == null || module.trim().length() == 0) {
			module = clazz.getName();
			config.setModule(module);
		}

		String encoding = config.getEncoding();
		int timeout = config.getTimeout();

		String cacheKey = String.format("module=%s&&encoding=%s&&timeout=%d", module, encoding, timeout);

		InvocationHandler rpcInvoker = invokerCache.get(cacheKey);
		Class<T>[] interfaces = new Class[] { clazz };
		if (rpcInvoker == null) {
			rpcInvoker = this;
			invokerCache.put(cacheKey, rpcInvoker);
		}
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		return (T) Proxy.newProxyInstance(classLoader, interfaces, this);
	}
	
}